<?php

namespace App\Services\Bank;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use SimpleXMLElement;

class BankApiClient
{
    private BankApiConfig $config;
    private Client $httpClient;

    public function __construct(BankApiConfig $config)
    {
        $this->config = $config;
        $this->httpClient = new Client([
            'timeout' => $config->getConfig('timeout'),
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded',
                'Accept' => 'text/xml',
            ],
        ]);
    }

    /**
     * 构建请求报文
     */
    public function buildRequestMessage(string $tradeCode, array $mapData = [], array $loopData = []): string
    {
        $xml = new \DOMDocument('1.0', 'UTF-8');
        $xml->formatOutput = false;

        // 创建根元素
        $body = $xml->createElement('body');
        $xml->appendChild($body);

        // 创建head部分
        $head = $xml->createElement('head');
        $head->appendChild($xml->createElement('erpSysCode', $this->config->getErpSysCode()));
        $head->appendChild($xml->createElement('custNo', $this->config->getCustNo()));
        $head->appendChild($xml->createElement('tradeName', $tradeCode));
        $body->appendChild($head);

        // 创建map部分（如果有数据）
        if (!empty($mapData)) {
            $map = $xml->createElement('map');
            foreach ($mapData as $key => $value) {
                // 清理禁用字符
                $cleanValue = $this->config->cleanString((string)$value);
                $map->appendChild($xml->createElement($key, htmlspecialchars($cleanValue, ENT_XML1)));
            }
            $body->appendChild($map);
        }

        // 创建loopData部分（如果有数据）
        if (!empty($loopData)) {
            $loopDataElement = $xml->createElement('loopData');
            foreach ($loopData as $rowData) {
                $row = $xml->createElement('row');
                foreach ($rowData as $key => $value) {
                    // 清理禁用字符
                    $cleanValue = $this->config->cleanString((string)$value);
                    $row->appendChild($xml->createElement($key, htmlspecialchars($cleanValue, ENT_XML1)));
                }
                $loopDataElement->appendChild($row);
            }
            $body->appendChild($loopDataElement);
        }

        $xmlString = $xml->saveXML();
        
        // 是否需要报文头
        if ($this->config->getConfig('with_header')) {
            return $this->addMessageHeader($xmlString, $tradeCode);
        }

        return $xmlString;
    }

    /**
     * 添加报文头
     */
    private function addMessageHeader(string $xmlContent, string $tradeCode): string
    {
        $messageType = $this->config->getConfig('message_type');
        $contentToMeasure = $messageType . $tradeCode . $xmlContent;
        $length = strlen($contentToMeasure);
        $header = str_pad($length, 8, '0', STR_PAD_LEFT) . $messageType . $tradeCode;
        
        return $header . $xmlContent;
    }

    /**
     * 解析响应报文
     */
    public function parseResponseMessage(string $response): array
    {
        try {
            $xml = new SimpleXMLElement($response);
            
            $result = [
                'success' => false,
                'ret_code' => (string)$xml->head->retCode ?? '',
                'ret_msg' => (string)$xml->head->retMsg ?? '',
                'erp_sys_code' => (string)$xml->head->erpSysCode ?? '',
                'cust_no' => (string)$xml->head->custNo ?? '',
                'trade_name' => (string)$xml->head->tradeName ?? '',
                'map_data' => [],
                'loop_data' => [],
            ];

            // 解析是否成功
            $result['success'] = $result['ret_code'] === '0';

            // 解析map数据
            if (isset($xml->map)) {
                foreach ($xml->map->children() as $element) {
                    $result['map_data'][$element->getName()] = (string)$element;
                }
            }

            // 解析loopData数据
            if (isset($xml->loopData)) {
                foreach ($xml->loopData->row as $row) {
                    $rowData = [];
                    foreach ($row->children() as $element) {
                        $rowData[$element->getName()] = (string)$element;
                    }
                    $result['loop_data'][] = $rowData;
                }
            }

            return $result;

        } catch (\Exception $e) {
            Log::error('Bank API response parse error', [
                'operation' => 'PARSE_RESPONSE',
                'response' => $response,
                'exception' => $e->getMessage(),
            ]);

            return [
                'success' => false,
                'ret_code' => 'PARSE_ERROR',
                'ret_msg' => '响应报文解析失败: ' . $e->getMessage(),
                'erp_sys_code' => '',
                'cust_no' => '',
                'trade_name' => '',
                'map_data' => [],
                'loop_data' => [],
            ];
        }
    }

    /**
     * 发送请求
     */
    public function sendRequest(string $message): array
    {
        try {
            Log::info('Sending request to bank API', [
                'operation' => 'HTTP_REQUEST',
                'url' => $this->config->getApiUrl(),
                'message_length' => strlen($message),
                'message_preview' => $message,
            ]);

            $startTime = microtime(true);
            $response = $this->httpClient->post($this->config->getApiUrl(), [
                'body' => $message,
            ]);
            $endTime = microtime(true);
            $duration = round(($endTime - $startTime) * 1000, 2);

            $responseBody = $response->getBody()->getContents();

            Log::info('Received response from bank API', [
                'operation' => 'HTTP_RESPONSE',
                'status_code' => $response->getStatusCode(),
                'response_length' => strlen($responseBody),
                'duration_ms' => $duration,
                'response_preview' => $responseBody,
            ]);

            return $this->parseResponseMessage($responseBody);

        } catch (GuzzleException $e) {
            Log::error('Bank API request error', [
                'operation' => 'HTTP_REQUEST',
                'url' => $this->config->getApiUrl(),
                'message_length' => strlen($message),
                'exception_type' => get_class($e),
                'exception_code' => $e->getCode(),
                'exception_message' => $e->getMessage(),
            ]);

            return [
                'success' => false,
                'ret_code' => 'REQUEST_ERROR',
                'ret_msg' => '网络请求失败: ' . $e->getMessage(),
                'erp_sys_code' => '',
                'cust_no' => '',
                'trade_name' => '',
                'map_data' => [],
                'loop_data' => [],
            ];
        }
    }

    /**
     * 通用API调用方法
     */
    public function callApi(string $operation, array $mapData = [], array $loopData = []): array
    {
        $tradeCode = $this->config->getTradeCode($operation);
        
        if (empty($tradeCode)) {
            return [
                'success' => false,
                'ret_code' => 'INVALID_OPERATION',
                'ret_msg' => '无效的操作类型: ' . $operation,
                'erp_sys_code' => '',
                'cust_no' => '',
                'trade_name' => '',
                'map_data' => [],
                'loop_data' => [],
            ];
        }

        $message = $this->buildRequestMessage($tradeCode, $mapData, $loopData);
        return $this->sendRequest($message);
    }
}